﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PSIEpics;
using epics_server_remoting_class;
using JEpicsServer_driver;
using string_short;
using JtextEpicsInterface;

namespace jtext_EpicsServer
{
    //this does not contian self scan and hardwere support
    //just basic function that ESRC already has
    //but wrap in here to make build a ioc easier
    //and it support str_short operation
    /// <summary>
    /// this make the array record whic is very different from normal one look really the same, server handles them like no different.
    /// they have the same parent,and overload some critical functions.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class JEpicsArray<T> : JEpicsRecord
    {
        //protected EpicsServer_Remoting ParentRemoteServer;  //this will work with the ESRC(EpicsServer_Remoting) instead of the JEpicsServer
        // JEpicsDriver MyEJDriver; //each record has its own JEDriver this handles the hardware job

        /// <summary>
        /// the same as it's parents the different is it'a a array with specified type T.
        /// <seealso cref="JEpicsRecord"/>
        /// </summary>
        public new T[] ValA;   //the raw value before proccessed by plugin
        /// <summary>
        /// the same as it's parents the different is it'a a array with specified type T.
        /// <seealso cref="JEpicsRecord"/>
        /// </summary>
        private new T[] ValB;  //the proccessed value  prossecced by plugin

        /// <summary>
        /// the lenth of the array record
        /// </summary>
        private int Lenth;
        /// <summary>
        /// Initializes a new instance of the <see cref="JEpicsArray&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="myserver">The remoting server for this record.</param>
        /// <param name="my_RP">The Record property.</param>
        /// <param name="Driver">The driver.</param>
        /// <param name="jeServer">The JtextEpics server.</param>
        public JEpicsArray(EpicsServer_Remoting myserver, Record_prop my_RP, IJEDriver Driver, JEpicsServer jeServer): base(myserver, my_RP)
        {
            
            ParentRemoteServer = myserver;
            MyPvName = my_RP.pvName;
            myRecordProp = my_RP;
            myDriver = Driver;
            //myPlugIN = PlugIn;
            myParentServer = jeServer;
            Lenth = myRecordProp.ArrayLen;
            ParentRemoteServer.addRecordArray<T>(my_RP.pvName,my_RP.ArrayLen , true,my_RP);
        }


        /// <summary>
        /// start every thing of this record
        /// <seealso cref="JEpicsRecord"/>
        /// </summary>
        /// <returns>if successful</returns>
        public override  bool IniRecord()
        {
            //after this  the record willbe running 
            //if not flushed by server it flush itself at his own rate create scan thread here
            //test code
            iniPlugIns();
            if (IniRecordDriver() == true)
            {
                IsRunning = true;
            }
            ValA = (T[])PVAL;   //you have to gave the Vala,B the initial value
            ValB = (T[])PVAL;
            return IsRunning;
        }


        /// <summary>
        /// Gets the array.Get a part of the array you name it;
        /// </summary>
        /// <param name="start">The start,position.</param>
        /// <param name="end">The end,position.</param>
        /// <returns></returns>
        public T[] GetArray(int start, int end)  //the function is more efficient then the property
        {
            return ParentRemoteServer.getRecordArray<T>(MyPvName,start,end);
        }

        /// <summary>
        /// Sets the array.Set part of a array you name it;
        /// </summary>
        /// <param name="Val">The value array.</param>
        /// <param name="begin_src">The begining position of the source array.</param>
        /// <param name="begin_des">The begin destination array.</param>
        /// <param name="lenth">The lenth you want to copy.</param>
        public void SetArray(T[] Val, int begin_src, int begin_des, int lenth)
        {
             ParentRemoteServer.setRecordArray<T>(MyPvName ,Val,begin_src,begin_des,lenth);
        }

        /// <summary>
        /// Gets or sets the PV val,not if it a input record it will override this PV value by VAL.
        /// much simpler then getArry setArray,but slower and less flexibile.
        /// </summary>
        /// <value>
        /// The PV value ,it's a array.
        /// </value>
        public override object PVAL  //should return T[]
        {
            get
            {
               return  ParentRemoteServer.getRecordArray<T>(MyPvName);
            }
            set
            {
                ParentRemoteServer.setRecordArray<T>(MyPvName, ((T[])value), 0, 0, ((T[])value).Length);
            }
        }
        /// <summary>
        /// Gets or sets the VAL.
        /// <para>this val is not the pv value,it the val the is not been proceessed by Pluguin</para>
        /// 	<para>For output this is equals to PV value ,youcan change this to meet the hardware output</para>
        /// 	<para>For input if the raw value from the hardware,you can this it will be put into PV later</para>
        /// </summary>
        /// <value>
        /// The VAL.
        /// </value>
        public override object VAL
        {
            get
            {
                return ValB;
            }
            set
            {
                ValB = (T[])value;
            }
        }



 
        #region epics message




        //public byte[] GetByte(int len)
        //{
        //    //this will get the message arrary recorde
        //    //and turn it to byte
        //    object msg;
        //    byte[] msgByte;
        //    msg = this.GetArray(0, len - 1);
        //    msgByte = Str_Short.splitShorts(((short[])msg));
        //    return msgByte;
        //}

        //public string GetString(int len)
        //{
        //    //this will get the message arrary recorde
        //    //and turn it to string
        //    string msgStr;
        //    object msg;
        //    if (len == 0)
        //    {
        //        msg = Val;
        //        msgStr = Str_Short.ShortToString(((short[])msg));
        //        return msgStr;
        //    }
        //    else
        //    {
        //        msg = this.GetArray(0, len - 1);
        //        msgStr = Str_Short.ShortToString(((short[])msg));
        //        return msgStr;
        //    }
        //}


        //---------------------------------------------------

        /// <summary>
        /// Gets the byte array.
        /// <para>if the array is byte you can use this ,Becouse the PSIEpics doesnot support byte,so youwill have to use sbyte instead,this funtion return byte no convter is needed</para>
        /// </summary>
        /// <param name="len">The lenth ,start from 0,youhave to pass this argument,0 is not allowed.</param>
        /// <returns></returns>
        public  byte[] GetByte(int len)
        {
            //this will get the message arrary recorde
            //and turn it to byte
            object msg;
            byte[] msgByte;
            msg = this.GetArray(0,len-1);
            msgByte = Str_Short.SByteToByte((sbyte[])msg);
            return msgByte;
        }

        /// <summary>
        /// Gets the string.
        /// <para>if the array is used to store string, you can use this ,Becouse the PSIEpics doesnot support byte,so youwill have to use sbyte instead,this funtion return string no convter is needed</para>
        /// </summary>
        /// <param name="len">The lenth if you pass "0",then the whole array is used.</param>
        /// <returns></returns>
        public  string GetString(int len)
        {
            //this will get the message arrary recorde
            //and turn it to string
            string msgStr;
            object msg;
            if (len == 0)
            {
                msg = PVAL;
                msgStr = Str_Short.SByteToString((sbyte[])msg);
                return msgStr;
            }
            else
            {
                msg = this.GetArray(0, len - 1);
                msgStr = Str_Short.SByteToString((sbyte[])msg);
                return msgStr;
            }
        }
        #endregion

        #region flush


        /// <summary>
        ///for input first hard->valA
        ///for output first PV->vaLa
        /// </summary>
        public override void Flush()
        {
            //for input first hard->valA
            //for output first PV->vaLa
            if (IsRunning == false)
                return;
            //Console.WriteLine("no drviver to inputFlush1");   //test code
            if (IsInput == true)
            {
                //for input first hard->valA
                if (myDriver != null)
                {
                    ValA = (T[])myDriver.GetVal(myRecordProp);
                    ValB = ValA;
                    //Console.WriteLine("inputFlush1");   //test code
                }
                else
                {
                    ValA = (T[])PVAL;
                    ValB = ValA;
                }
            }
            else
            {   //for output first PV->vaLa
                ValA = (T[])PVAL;
                ValB = ValA;
                //Console.WriteLine("outputFlush1");   //test code
            }
        }

        /// <summary>
        ///for input then valb->PV
        ///for output then valB->hard
        /// </summary>
        public override void Flush2()
        {
            //for input then valb->PV
            //for output then valB->hard
            if (IsRunning == false)
                return;

            if (IsInput == true)
            {
                //for input then valb->PV
                PVAL = ValB;
                //Console.WriteLine("inputFlush2");   //test code
            }
            else
            {   //for output first PV->vaLa
                if (myDriver != null)
                {
                    myDriver.SetVal(myRecordProp, ValB);
                    //Console.WriteLine("putputFlush2");   //test code
                }
                else
                {
                    PVAL = ValB;
                }
            }
        }





        #endregion


        /// <summary>
        /// dispose this record
        /// </summary>
        public override  void  Dispose()
        {
            IsRunning = false;
            ParentRemoteServer.disposeRecordArray<T>(MyPvName);
        }
        



     





    }
}
